package csp

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

var (
	client = http.Client{
		Timeout: time.Duration(5 * time.Second),
	}
)

type SiteResp struct {
	Err    error
	Url    string
	Resp   string
	Status int
	Cost   int64
}

//构造请求
func doSiteRequest(out chan<- SiteResp, url string) {
	res := SiteResp{
		Url: url,
	}
	startAt := time.Now()
	defer func() {
		res.Cost = time.Since(startAt).Milliseconds()
		out <- res
	}()

	resp, err := client.Get(url)
	if resp != nil {
		res.Status = resp.StatusCode
		//res.Url = url
	}
	if err != nil {
		res.Err = err
		return
	}

	_, err = ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		res.Err = err
		return
	}
}

//合并结果
func mergeResponse(resp <-chan SiteResp, ret *[]SiteResp, down chan struct{}) {
	defer func() {
		down <- struct{}{}
	}()

	count := 0
	for v := range resp {
		*ret = append(*ret, v)
		count++
		//填充完成，返回
		if count == cap(*ret) {
			return
		}
	}
}

//barrier屏障模式，阻塞直到聚合所有goroutine返回结果
func BatchSiteRequest() {
	endpoints := []string{
		"https://baidu.com",
		"https://www.163.com",
		"https://www.jd.com",
		"https://www.github.com",
	}

	//一个endpoin返回一个结果，缓冲可以确定
	respChan := make(chan SiteResp, len(endpoints))
	defer close(respChan)

	//并行爬取
	for _, endpoints := range endpoints {
		go doSiteRequest(respChan, endpoints)
	}

	//聚合结果，返回结束事件，避免轮询
	down := make(chan struct{})
	ret := make([]SiteResp, 0, len(endpoints))
	go mergeResponse(respChan, &ret, down)

	//等待结束
	<-down

	for _, v := range ret {
		fmt.Println(v)
	}
}

//func main() {
//	BatchSiteRequest()
//
//}
